package programs;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

/**
 * 生产者消费者 -- 阻塞队列
 */
public class Producer_Customer {

    public static void main1(String[] args) throws InterruptedException {
        BlockingDeque<String> queue = new LinkedBlockingDeque<>();
        queue.put("hello");// 可能会触发阻塞
        String s = queue.take();// 出队列
    }
    public static void main2(String[] args) throws InterruptedException {
        MyBlockingQueue queue = new MyBlockingQueue();
        queue.put(1);
        queue.put(2);
        queue.put(3);
        queue.put(4);
        System.out.println(queue.take());
        System.out.println(queue.take());
        System.out.println(queue.take());
        System.out.println(queue.take());
    }


    private static MyBlockingQueue queue = new MyBlockingQueue();
    public static void main(String[] args) {

        // 生产者线程
        Thread producer = new Thread(() -> {
            int num = 0;
            while (true) {
                try {
                    System.out.println("生产了 " + num);
                    queue.put(num);
                    num++;
                    // 生产慢
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        producer.start();

        // 消费者线程
        Thread customer = new Thread(() -> {
            while (true) {
                try {
                    // 消费慢
//                    Thread.sleep(500);
                    int num = queue.take();
                    System.out.println("消费了 " + num);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        customer.start();
    }
}
// 实现一个阻塞队列
class MyBlockingQueue{
    // 数组 -- 循环队列
    private int[] data = new int[1000];
    private int size = 0;// 元素个数
    private int head;// 队首下标
    private int tail;// 队尾下标

    // 入队列
    // 每个都在操作公共变量,就给整个方法加锁
    public synchronized void put(int val) throws InterruptedException {
        if (size == data.length){
            // 队列满
            wait();
        }
        data[tail] = val;
        tail++;
        if (tail >= data.length){
            tail = 0;
        }
        size++;
        // 队列里有元素了，唤醒 take()
        notify();
    }
    // 出队列
    public synchronized Integer take() throws InterruptedException {
        if (size == 0){
            wait();
        }
        int val = data[head];
        head++;
        if (head >= data.length){
            head = 0;
        }
        size--;
        // 队列里可以元素了，唤醒 put()
        notify();
        return val;
    }
}
